package main

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	contextPath    = `/ui/`
	baseURL        = "https://coff.sadld.cn"
	comicsBaseURL  = `https://thinkskill.cdn.bcebos.com/`
	chapterContent = urlConfig{
		url:  `/api/chapter/getByNumber`,
		cate: 1,
	}
)

var (
	Err404 = errors.New("file not found")
)

type urlConfig struct {
	url  string
	cate int //type
}

type param struct {
	NavigationType int    `json:"navigationType"` //1
	ParentId       string `json:"parentId"`       //小说id
	Number         int    `json:"number"`         //章节序号（从1开始）
	Url            string `json:"url"`            //urlConfig.url = /api/chapter/getByNumber
	Time           string `json:"time"`           // "" + 年 + 月 + 日 + 时 = 202482317
}

type response struct {
	Code   int    `json:"code"`
	Data   Data   `json:"data"`
	Number int    `json:"number"`
	Title  string `json:"title"`
}

type Data struct {
	Content string `json:"content"`
}

// 获取图片内容
func getImageContent(url string) (string, error) {
	url = comicsBaseURL + strings.TrimPrefix(url, "/")
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if resp.StatusCode == http.StatusNotFound {
		return "", Err404
	}
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// 获取图片url列表
func getChapterImageURL(novelId string, chapterIndex int) ([]string, error) {
	var images []string
	r, err := requestEncoder(chapterContent, param{
		NavigationType: 1,
		ParentId:       novelId,
		Number:         chapterIndex,
		Url:            "",
		Time:           "",
	})
	if err != nil {
		return images, fmt.Errorf("request encoder error: %w", err)
	}
	raw, err := http.Get(buildRequestURL(getStringFingerprint(r)) + "?data=" + r)
	if err != nil {
		return images, fmt.Errorf("request error: %w", err)
	}
	if raw.StatusCode != 200 {
		return images, fmt.Errorf("status code error: %w", errors.New(strconv.Itoa(raw.StatusCode)))
	}
	body, err := io.ReadAll(raw.Body)
	if err != nil {
		return images, fmt.Errorf("ready body error: %w", err)
	}
	rspText, err := responseDecoder(string(body))
	if err != nil {
		return images, fmt.Errorf("decode body error: %w", err)
	}
	var rsp response
	err = json.Unmarshal([]byte(rspText), &rsp)
	if err != nil {
		return images, fmt.Errorf("unmarshal response error: %w", err)
	}
	if rsp.Code != 200 {
		return images, fmt.Errorf("response code error: %w", errors.New(strconv.Itoa(rsp.Code)))
	}

	err = json.Unmarshal([]byte(rsp.Data.Content), &images)
	if err != nil {
		return images, fmt.Errorf("unmarshal content error: %w", err)
	}
	return images, nil
}

// 请求数据加密
func requestEncoder(uc urlConfig, pa param) (string, error) {
	pa.Url = uc.url
	now := time.Now()
	pa.Time = fmt.Sprintf("%d%d%d%d", now.Year(), now.Month(), now.Day(), now.Hour())
	jsonParam, err := json.Marshal(pa)
	if err != nil {
		return "", err
	}
	paramR := base64.URLEncoding.EncodeToString([]byte(urlEncodeForJS(jsonParam)))
	paramG := len(paramR) / 10
	var paramQ []string
	paramE := 0
	for i := 0; i <= 10; i++ {
		h := i * paramG
		//b := k == 1 ? "A" : Net.randomString(1);
		b := "A"
		p := paramR[paramE:h]
		paramQ = append(paramQ, p)
		paramQ = append(paramQ, b)
		paramE = h
	}
	paramQ = append(paramQ, paramR[paramE:])
	return strings.Join(paramQ, ""), nil
}

func urlEncodeForJS(s []byte) string {
	encoded := url.QueryEscape(string(s))
	return strings.ReplaceAll(encoded, "+", "%20")
}

func getStringFingerprint(s string) string {
	var e int32 = 0
	for _, r := range s {
		e = ((e << 5) - e) + int32(r)
	}
	a := strconv.FormatInt(int64(e), 16)
	return a
}

func buildRequestURL(fp string) string {
	d := time.Now()
	i := fmt.Sprintf("%d%d%d%d_%s", d.Year(), d.Month(), d.Year(), d.Hour(), fp)
	return fmt.Sprintf("%s%sopen_api/data_%s.js", baseURL, contextPath, i)
}

// 解码响应
func responseDecoder(rawRSP string) (string, error) {
	re := regexp.MustCompile(`\s+`)
	var rsp []string
	e := len(rawRSP) - 10
	g := e / 10
	h := 0
	for c := 0; c < 10; c++ {
		b := c*g + 1 + c
		d := reverseString(rawRSP[b : b+g])
		rsp = append(rsp, d)
		h = b + g
	}
	rsp = append(rsp, reverseString(rawRSP[h+1:]))
	rspTxt := strings.Join(rsp, "")
	b4Decode, err := base64.StdEncoding.DecodeString(rspTxt)
	if err != nil {
		return "", err
	}
	decodeRsp, err := url.QueryUnescape(string(b4Decode))
	if err != nil {
		return "", err
	}
	decodeRsp = re.ReplaceAllString(decodeRsp, " ")
	return decodeRsp, nil
}

// 反转字符串
func reverseString(s string) string {
	ss := strings.Split(s, "")
	for i, j := 0, len(ss)-1; i < j; i, j = i+1, j-1 {
		ss[i], ss[j] = ss[j], ss[i]
	}
	return strings.Join(ss, "")
}
